package com.opensourceedge.phonebook.api;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

public class FileStore implements Store {

	File file;

	public FileStore(String fileLocation) {
		file = new File("contacts.txt");
		if (!file.exists()) {
			try {
				System.out.println("Creating new file to store data path="+file.getAbsolutePath());
				file.createNewFile();
			} catch (IOException e) {
				System.out.println("Failed to create file in current location move application to your user folder.");
			}
		}
	}

	/*
	 * Stores new Contact into file.
	 * 
	 * @see
	 * com.opensourceedge.phonebook.api.ContactStore#insert(com.opensourceedge
	 * .phonebook.api.Contact)
	 */
	public void insert(Contact newContact) {
		this.writeContactToFile(newContact, file);
	}

	private void writeContactToFile(Contact newContact, File file) {
		try {
			if (newContact.getContactID() == 0) {
				newContact.setContactID(this.getLastContactID() + 1);
			}

			String data = FileStore.parseContactToString(newContact);

			// if file doesn't exists, then create it
			if (!file.exists()) {
				file.createNewFile();
			}

			// true = append file
			FileWriter fileWritter = new FileWriter(file.getName(), true);
			BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
			bufferWritter.write(data);
			bufferWritter.close();

			//System.out.println("Done");

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void delete(int idToDelete) {
		File temp = new File("newContact.txt");

		try {
			Scanner sn = new Scanner(file);
			sn.useDelimiter(";");

			while (sn.hasNext()) {
				// extracts contact object from scanner pointer location.
				Contact ct = FileStore.extractContact(sn);

				if (ct.getContactID() != idToDelete) {
					this.writeContactToFile(ct, temp);
				}
			}
			sn.close();
			String oldName=file.getName();
			file.delete();
			temp.renameTo(new File(oldName));
			file = temp;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void update(Contact newContact) {
		File temp = new File("newContact.txt");

		try {
			Scanner sn = new Scanner(file);
			sn.useDelimiter(";");

			while (sn.hasNext()) {
				// extracts contact object from scanner pointer location.
				Contact ct = FileStore.extractContact(sn);

				if (ct.getContactID() != newContact.getContactID()) {
					this.writeContactToFile(ct, temp);
				} else {
					this.writeContactToFile(newContact, temp);
				}
			}
			sn.close();
			String oldName=file.getName();
			file.delete();
			temp.renameTo(new File(oldName));
			file = temp;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public Contact select(int id) {
		Contact contact = null;

		try {
			Scanner sn = new Scanner(file);
			sn.useDelimiter(";");

			while (sn.hasNext()) {
				// extracts contact object from scanner pointer location.
				Contact ct = FileStore.extractContact(sn);

				if (ct.getContactID() == id) {
					contact = ct;
					break;
				}
			}
			sn.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return contact;
	}

	@Override
	public ArrayList<Contact> getAll() {
		ArrayList<Contact> list = new ArrayList<>();
		try {
			Scanner sn = new Scanner(file);
			sn.useDelimiter(";");

			while (sn.hasNext()) {
				// extracts contact object from scanner pointer location.
				Contact ct = FileStore.extractContact(sn);
				// adds extracted Contact object to list.
				list.add(ct);
			}
			sn.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}

	@Override
	public ArrayList<Contact> search(String tag) {
		ArrayList<Contact> list = new ArrayList<>();

		try {
			Scanner sn = new Scanner(file);
			sn.useDelimiter(";");

			while (sn.hasNext()) {
				// extracts contact object from scanner pointer location.
				Contact ct = FileStore.extractContact(sn);

				/*
				 * converts Contact class to string and compares with search
				 * tag.
				 */
				if (FileStore.parseContactToString(ct).toLowerCase()
						.matches(".*" + tag.toLowerCase() + ".*")) {
					list.add(ct);
				}
			}
			sn.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}

	@Override
	public Contact next(int id) {
		Contact contact = null;

		try {
			Scanner sn = new Scanner(file);
			sn.useDelimiter(";");

			while (sn.hasNext()) {
				// extracts contact object from scanner pointer location.
				Contact ct = FileStore.extractContact(sn);

				/*
				 * converts Contact class to string and compares with search
				 * tag.
				 */
				if (ct.getContactID() == id) {
					contact = ct;
				}
			}
			sn.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return contact;
	}

	/*
	 * converts Contact to String so that it can be written to file. as well as
	 * adds ; as separator.
	 */
	public static String parseContactToString(Contact con) {

		String str = new String().concat(con.getContactID() + ";")
				.concat(con.getBuildingNumber() + ";")
				.concat(con.getCity() + ";").concat(con.getCompanyName() + ";")
				.concat(con.getFirstName() + ";")
				.concat(con.getLastName() + ";")
				.concat(con.getMobilePhone() + ";")
				.concat(con.getState() + ";").concat(con.getStreetName() + ";")
				.concat(con.getWorkPhone() + ";")
				.concat(con.getZipCode() + ";");
		//System.out.println(con + " converted to String as " + str);
		return str;
	}

	/*
	 * Extracts single Contact object from scanner. -->Generated as a result of
	 * refactoring.
	 */
	public static Contact extractContact(Scanner sn) throws Exception {
		Contact ct = new Contact();

		ct.setContactID(sn.nextInt());
		ct.setBuildingNumber(sn.next());
		ct.setCity(sn.next());
		ct.setCompanyName(sn.next());
		ct.setFirstName(sn.next());
		ct.setLastName(sn.next());
		ct.setMobilePhone(sn.next());
		ct.setState(sn.next());
		ct.setStreetName(sn.next());
		ct.setWorkPhone(sn.next());
		ct.setZipCode(sn.next());

		return ct;
	}

	/*
	 * returns last contact id from fileStore if no contacts found returns 1.
	 */
	public int getLastContactID() {
		Contact contact = null;

		try {
			Scanner sn = new Scanner(file);
			sn.useDelimiter(";");

			while (sn.hasNext()) {
				// extracts contact object from scanner pointer location.
				Contact ct = FileStore.extractContact(sn);
				contact = ct;
			}
			sn.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (contact == null) {
			return 0;
		}
		return contact.getContactID();
	}
}
